source('../settings/settings.R')
source('commonFunctions.R')
library(nlme)
library(lme4)
set.seed(43)
drive1 <- read.csv('../data/processed/analysis/TT1_Drive_1_PP.csv')
drive2 <- read.csv('../data/processed/Analysis/TT1_Drive_2_PP.csv')
drive3 <- read.csv('../data/processed/Analysis/TT1_Drive_3_PP.csv')
drive4 <- read.csv('../data/processed/Analysis/TT1_Drive_4_PP.csv', stringsAsFactors = T)
dfSeg <- data.frame(rep(1, nrow(drive4)), rep(2, nrow(drive4)), rep(3, nrow(drive4)), rep(4, nrow(drive4)))
names(dfSeg) <- c("Seg1", "Seg2", "Seg3", "Seg4")

combinedDf_Seg1 <- cbind(drive4, 
                    drive1$MeanPP_Seg0, 
                    drive2$MeanPP_Seg1, drive3$MeanPP_Seg1, 
                    drive2$MeanPP_Seg0_1, drive3$MeanPP_Seg0_1,
                    drive2$StdPP_Seg1, drive3$StdPP_Seg1,
                    drive2$StdPP_Seg0_1, drive3$StdPP_Seg0_1,
                    drive2$MeanPP_AccHigh1, drive3$MeanPP_AccHigh1,
                    drive2$X.MeanPP_AccLow1, drive3$X.MeanPP_AccLow1,
                    drive2$StdPP_AccHigh1, drive3$StdPP_AccHigh1,
                    drive2$StdPP_AccLow1, drive3$StdPP_AccLow1,
                    dfSeg$Seg1
                  )
combinedDf_Seg2 <- cbind(drive4, 
                    drive1$MeanPP_Seg0, 
                    drive2$MeanPP_Seg2, drive3$MeanPP_Seg2, 
                    drive2$MeanPP_Seg0_2, drive3$MeanPP_Seg0_2,
                    drive2$StdPP_Seg2, drive3$StdPP_Seg2,
                    drive2$StdPP_Seg0_2, drive3$StdPP_Seg0_2,
                    drive2$MeanPP_AccHigh2, drive3$MeanPP_AccHigh2,
                    drive2$X.MeanPP_AccLow2, drive3$X.MeanPP_AccLow2,
                    drive2$StdPP_AccHigh2, drive3$StdPP_AccHigh2,
                    drive2$StdPP_AccLow2, drive3$StdPP_AccLow2,
                    dfSeg$Seg2
                  )
combinedDf_Seg3 <- cbind(drive4, 
                    drive1$MeanPP_Seg0, 
                    drive2$MeanPP_Seg3, drive3$MeanPP_Seg3, 
                    drive2$MeanPP_Seg0_3, drive3$MeanPP_Seg0_3,
                    drive2$StdPP_Seg3, drive3$StdPP_Seg3,
                    drive2$StdPP_Seg0_3, drive3$StdPP_Seg0_3,
                    drive2$MeanPP_AccHigh3, drive3$MeanPP_AccHigh3,
                    drive2$X.MeanPP_AccLow3, drive3$X.MeanPP_AccLow3,
                    drive2$StdPP_AccHigh3, drive3$StdPP_AccHigh3,
                    drive2$StdPP_AccLow3, drive3$StdPP_AccLow3,
                    dfSeg$Seg3
                  )
combinedDf_Seg4 <- cbind(drive4, 
                    drive1$MeanPP_Seg0, 
                    drive2$MeanPP_Seg4, drive3$MeanPP_Seg4, 
                    drive2$MeanPP_Seg0_4, drive3$MeanPP_Seg0_4,
                    drive2$StdPP_Seg4, drive3$StdPP_Seg4,
                    drive2$StdPP_Seg0_4, drive3$StdPP_Seg0_4,
                    drive2$MeanPP_AccHigh4, drive3$MeanPP_AccHigh4,
                    drive2$X.MeanPP_AccLow4, drive3$X.MeanPP_AccLow4,
                    drive2$StdPP_AccHigh4, drive3$StdPP_AccHigh4,
                    drive2$StdPP_AccLow4, drive3$StdPP_AccLow4,
                    dfSeg$Seg4
                  )

common_names <- c("PP_Dev_1_Turning",
                  "PP_Dev_2_Straight", "PP_Dev_3_Straight", 
                  "PP_Dev_2_Turning", "PP_Dev_3_Turning", 
                  "Std_PP_2_Straight", "Std_PP_3_Straight", 
                  "Std_PP_2_Turning", "Std_PP_3_Turning",
                  
                  "Mean_PP_2_AccHigh", "Mean_PP_3_AccHigh",
                  "Mean_PP_2_AccLow", "Mean_PP_3_AccLow",
                  "Std_PP_2_AccHigh", "Std_PP_3_AccHigh",
                  "Std_PP_2_AccLow", "Std_PP_3_AccLow",
                  
                  "Segment")

names(combinedDf_Seg1) <- c(names(drive4), common_names)
names(combinedDf_Seg2) <- c(names(drive4), common_names)
names(combinedDf_Seg3) <- c(names(drive4), common_names)
names(combinedDf_Seg4) <- c(names(drive4), common_names)

# combinedDf_Seg1$Subject <- paste0(as.factor(combinedDf_Seg1$Subject), ".S1")
# combinedDf_Seg2$Subject <- paste0(as.factor(combinedDf_Seg2$Subject), ".S2")
# combinedDf_Seg3$Subject <- paste0(as.factor(combinedDf_Seg3$Subject), ".S3")
# combinedDf_Seg4$Subject <- paste0(as.factor(combinedDf_Seg4$Subject), ".S4")

combinedDf <- rbind(combinedDf_Seg1, combinedDf_Seg2, combinedDf_Seg3, combinedDf_Seg4)

# combinedDf$Subject <- paste0("#", str_pad(combinedDf$Subject, 2, pad="0"))
combinedDf$Segment <- as.factor(combinedDf$Segment)
combinedDf$ActivityEncoded <- factor(ifelse(combinedDf$Activity == "NO", "1", ifelse(combinedDf$Activity == "C", "2", "3")))

combinedDf <- combinedDf[complete.cases(combinedDf),]
combinedDf$Subject = as.factor(combinedDf$Subject)
model = lm(PP_After ~ 
              PP_Dev_2_Straight + 
              PP_Dev_3_Straight +
              PP_Dev_2_Turning + 
              PP_Dev_3_Turning + 
              Std_PP_2_Straight + 
              Std_PP_3_Straight + 
              Std_PP_2_Turning +
              Std_PP_3_Turning +
              # PP_Prior +
              factor(ActivityEncoded),
            data=combinedDf, random = ~1|factor(Subject), method = "REML")
method = 'REML' is not supported. Using 'qr'In lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
 extra argument ‘random’ will be disregarded
# anova(model)
summary(model)

Call:
lm(formula = PP_After ~ PP_Dev_2_Straight + PP_Dev_3_Straight + 
    PP_Dev_2_Turning + PP_Dev_3_Turning + Std_PP_2_Straight + 
    Std_PP_3_Straight + Std_PP_2_Turning + Std_PP_3_Turning + 
    factor(ActivityEncoded), data = combinedDf, method = "REML", 
    random = ~1 | factor(Subject))

Residuals:
     Min       1Q   Median       3Q      Max 
-0.17764 -0.07137  0.00092  0.05144  0.34502 

Coefficients:
                         Estimate Std. Error t value Pr(>|t|)    
(Intercept)              -0.02294    0.04870  -0.471   0.6393    
PP_Dev_2_Straight         0.68712    0.15583   4.410 4.45e-05 ***
PP_Dev_3_Straight        -0.37734    0.23618  -1.598   0.1155    
PP_Dev_2_Turning         -0.22015    0.14683  -1.499   0.1391    
PP_Dev_3_Turning          0.38632    0.22101   1.748   0.0857 .  
Std_PP_2_Straight         0.02144    0.38757   0.055   0.9561    
Std_PP_3_Straight         0.50369    0.36818   1.368   0.1765    
Std_PP_2_Turning         -0.08343    0.50205  -0.166   0.8686    
Std_PP_3_Turning         -0.95800    0.60836  -1.575   0.1207    
factor(ActivityEncoded)2  0.08647    0.03285   2.633   0.0108 *  
factor(ActivityEncoded)3  0.17032    0.03184   5.349 1.51e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.0993 on 59 degrees of freedom
Multiple R-squared:  0.5613,    Adjusted R-squared:  0.4869 
F-statistic: 7.548 on 10 and 59 DF,  p-value: 1.338e-07
plot(model)

No Random Effects

linearModel1 <- lm(PP_After ~ 
                Mean_PP_2_AccHigh
              + Mean_PP_2_AccLow
              + Mean_PP_3_AccHigh
              + Mean_PP_3_AccLow
              + Std_PP_2_AccHigh
              + Std_PP_2_AccLow
              + Std_PP_3_AccHigh
              + Std_PP_3_AccLow
              # + PP_Prior
              + factor(ActivityEncoded),
            data=combinedDf)

# anova(model)
summary(linearModel1)

Call:
lm(formula = PP_After ~ Mean_PP_2_AccHigh + Mean_PP_2_AccLow + 
    Mean_PP_3_AccHigh + Mean_PP_3_AccLow + Std_PP_2_AccHigh + 
    Std_PP_2_AccLow + Std_PP_3_AccHigh + Std_PP_3_AccLow + factor(ActivityEncoded), 
    data = combinedDf)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.143483 -0.066038 -0.007552  0.051595  0.300313 

Coefficients:
                         Estimate Std. Error t value Pr(>|t|)    
(Intercept)              -0.06552    0.03640  -1.800  0.07695 .  
Mean_PP_2_AccHigh         1.63376    0.50590   3.229  0.00203 ** 
Mean_PP_2_AccLow         -1.15253    0.49763  -2.316  0.02405 *  
Mean_PP_3_AccHigh         0.74436    0.31520   2.362  0.02152 *  
Mean_PP_3_AccLow         -0.66142    0.33913  -1.950  0.05589 .  
Std_PP_2_AccHigh         -1.28974    1.45755  -0.885  0.37982    
Std_PP_2_AccLow           0.79583    1.15728   0.688  0.49435    
Std_PP_3_AccHigh          0.15278    0.94374   0.162  0.87195    
Std_PP_3_AccLow           0.91693    0.83810   1.094  0.27838    
factor(ActivityEncoded)2  0.08724    0.03041   2.869  0.00571 ** 
factor(ActivityEncoded)3  0.14810    0.03043   4.867 8.83e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.09353 on 59 degrees of freedom
Multiple R-squared:  0.6108,    Adjusted R-squared:  0.5448 
F-statistic: 9.259 on 10 and 59 DF,  p-value: 5.37e-09
plot(linearModel1)

With Random Effects

linearModel1 <- lme(PP_After ~ 
                Mean_PP_2_AccHigh
              + Mean_PP_2_AccLow
              + Mean_PP_3_AccHigh
              + Mean_PP_3_AccLow
              + Std_PP_2_AccHigh
              + Std_PP_2_AccLow
              + Std_PP_3_AccHigh
              + Std_PP_3_AccLow,
              # + factor(ActivityEncoded),
              random=~1|factor(Subject),
            data=combinedDf)

# anova(model)
summary(linearModel1)
Linear mixed-effects model fit by REML
 Data: combinedDf 

Random effects:
 Formula: ~1 | factor(Subject)
        (Intercept)     Residual
StdDev:   0.1466446 2.557679e-17

Fixed effects: PP_After ~ Mean_PP_2_AccHigh + Mean_PP_2_AccLow + Mean_PP_3_AccHigh +      Mean_PP_3_AccLow + Std_PP_2_AccHigh + Std_PP_2_AccLow + Std_PP_3_AccHigh +      Std_PP_3_AccLow 
 Correlation: 
                  (Intr) M_PP_2_AH M_PP_2_AL M_PP_3_AH M_PP_3_AL S_PP_2_AH S_PP_2_AL S_PP_3_AH
Mean_PP_2_AccHigh -0.173                                                                      
Mean_PP_2_AccLow   0.172 -0.961                                                               
Mean_PP_3_AccHigh  0.035 -0.001    -0.023                                                     
Mean_PP_3_AccLow   0.048 -0.062     0.023    -0.694                                           
Std_PP_2_AccHigh  -0.061  0.155    -0.193     0.086    -0.076                                 
Std_PP_2_AccLow   -0.037  0.036    -0.019    -0.132     0.087    -0.873                       
Std_PP_3_AccHigh  -0.025  0.066    -0.117    -0.454     0.310    -0.336     0.191             
Std_PP_3_AccLow    0.060  0.191    -0.208     0.377    -0.323     0.302    -0.238    -0.528   

Standardized Within-Group Residuals:
       Min         Q1        Med         Q3        Max 
-5.4259302 -0.5425930  0.0000000  0.8138895  4.3407442 

Number of Observations: 70
Number of Groups: 21 
plot(linearModel1)

linearModel1 <- lm(PP_After ~ 
                Mean_PP_2_AccHigh
              + Mean_PP_2_AccLow
              + Mean_PP_3_AccHigh
              + Mean_PP_3_AccLow
              # + PP_Prior
              + factor(ActivityEncoded), 
            data=combinedDf)

# anova(model)
summary(linearModel1)

Call:
lm(formula = PP_After ~ Mean_PP_2_AccHigh + Mean_PP_2_AccLow + 
    Mean_PP_3_AccHigh + Mean_PP_3_AccLow + factor(ActivityEncoded), 
    data = combinedDf)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.14161 -0.06916 -0.00742  0.04809  0.30760 

Coefficients:
                         Estimate Std. Error t value Pr(>|t|)    
(Intercept)              -0.05248    0.02751  -1.907  0.06103 .  
Mean_PP_2_AccHigh         1.64939    0.38841   4.246 7.28e-05 ***
Mean_PP_2_AccLow         -1.14578    0.37518  -3.054  0.00331 ** 
Mean_PP_3_AccHigh         0.65161    0.26162   2.491  0.01540 *  
Mean_PP_3_AccLow         -0.60534    0.28421  -2.130  0.03709 *  
factor(ActivityEncoded)2  0.08906    0.02976   2.993  0.00394 ** 
factor(ActivityEncoded)3  0.15955    0.02892   5.516 6.92e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.09303 on 63 degrees of freedom
Multiple R-squared:  0.5888,    Adjusted R-squared:  0.5496 
F-statistic: 15.03 on 6 and 63 DF,  p-value: 1.372e-10
plot(linearModel1)

Machine Learning

ppAfter <- combinedDf$PP_After
ppAfterArray <- matrix(ppAfter, nrow = 1,ncol = length(ppAfter))
  
thresholdPPAfter <- otsu(ppAfterArray, range=c(min(ppAfter), max(ppAfter))) # Expected Threshold > 0.10123
print(paste0('Threshold: ', thresholdPPAfter))
[1] "Threshold: 0.101235546875"
selectedDf <- combinedDf %>% select(
                  "Subject", "Activity", "PP_After", # "PP_Prior",
                  "Mean_PP_2_AccHigh", "Mean_PP_3_AccHigh",
                  "Mean_PP_2_AccLow", "Mean_PP_3_AccLow",
                  "Std_PP_2_AccHigh", "Std_PP_3_AccHigh",
                  "Std_PP_2_AccLow", "Std_PP_3_AccLow")

selectedDf$Subject <- NULL
selectedDf$Activity_NO <- ifelse(selectedDf$Activity == "NO", 1, 0)
selectedDf$Activity_C <- ifelse(selectedDf$Activity == "C", 1, 0)
selectedDf$Activity_M <- ifelse(selectedDf$Activity == "M", 1, 0)
selectedDf$Activity <- NULL

# selectedDf$PP_Dev_1_Turning <- NULL
# selectedDf$Std_PP_2_Straight <- NULL
# selectedDf$Std_PP_2_Turning <- NULL
# selectedDf$Std_PP_3_Straight <- NULL
# selectedDf$Std_PP_3_Turning <- NULL
# 
# # According to Linear model
# selectedDf$PP_Dev_2_Straight <- abs(selectedDf$PP_Dev_2_Straight)
# selectedDf$PP_Dev_3_Straight <- abs(selectedDf$PP_Dev_3_Straight)
# selectedDf$PP_Dev_2_Turning <- abs(selectedDf$PP_Dev_2_Turning)
# selectedDf$PP_Dev_3_Turning <- abs(selectedDf$PP_Dev_3_Turning)
# selectedDf$PP_Prior <- abs(selectedDf$PP_Prior) # NULL

selectedDf$Class <- ifelse(selectedDf$PP_After >= thresholdPPAfter, T, F)
selectedDf$PP_After <- NULL

print(names(selectedDf))
 [1] "Mean_PP_2_AccHigh" "Mean_PP_3_AccHigh" "Mean_PP_2_AccLow"  "Mean_PP_3_AccLow"  "Std_PP_2_AccHigh"  "Std_PP_3_AccHigh" 
 [7] "Std_PP_2_AccLow"   "Std_PP_3_AccLow"   "Activity_NO"       "Activity_C"        "Activity_M"        "Class"            
# library(mefa)
# combinedDf <- rep(combinedDf, 10) 
set.seed(39)
n_folds <- 10
params <- param <- list(objective       = "binary:logistic", 
               booster          = "gbtree",
               eval_metric      = "auc",
               eta              = 0.1,
               max_depth        = 10,
               alpha            = 1,
               lambda           = 0,
               gamma            = 0.45,
               min_child_weight = 0.3,
               subsample        = 1,
               colsample_bytree = 1)
           
# XGBoost Model         
xgb_m <- xgb.cv(   params               = param,
                  data = as.matrix(selectedDf %>% select(-Class)) ,
                  label =  selectedDf$Class,
                  nrounds             = 100,
                  verbose             = F,
                  prediction          = T,
                  maximize            = F, # Change this value to F will help to run with more itineration
                  nfold               = n_folds,
                  metrics             = c("auc", "error"),
                  early_stopping_rounds = 50,
                  stratified            = T,
                  scale_pos_weight      = 1)

# xgb_m$evaluation_log[xgb_m$best_iteration,"test_auc_mean"]
xgb_m$evaluation_log[xgb_m$best_iteration,]
NA

Performance Metrics

# Prediction
selectedDf$clsPred <- round(xgb_m$pred)

computePerformanceResults <- function(sdat){
  sdat = sdat[complete.cases(sdat),]
  acc = sum(sdat[,1] == sdat[,2])/nrow(sdat)
  conf_mat = table(sdat)
  specif = conf_mat[1,1]/sum(conf_mat[,1])
  sensiv = conf_mat[2,2]/sum(conf_mat[,2])
  preci =  conf_mat[2,2]/sum(conf_mat[2,])
  npv =    conf_mat[1,1]/sum(conf_mat[1,])
  return(c(acc,specif,sensiv,preci,npv))
}

# Get average performance
performance <- computePerformanceResults(selectedDf %>% select(Class, clsPred))
acc <- performance[1]
prec <- performance[4]
recall <- performance[3]
spec <- performance[2]
npv <- performance[5]
f1 <- (2 * recall * prec) / (recall + prec)
auc <- as.numeric(xgb_m$evaluation_log[xgb_m$best_iteration, "test_auc_mean"])

print(paste("Accuracy=", round(acc, 2)))
[1] "Accuracy= 0.81"
print(paste("Precision=", round(prec, 2)))
[1] "Precision= 0.7"
print(paste("Recall=", round(recall, 2)))
[1] "Recall= 0.84"
print(paste("Specificity=", round(spec, 2)))
[1] "Specificity= 0.8"
print(paste("NPV=", round(npv, 2)))
[1] "NPV= 0.9"
print(paste("F1=", round(f1, 2)))
[1] "F1= 0.76"
print(paste("AUC=", round(auc, 2)))
[1] "AUC= 0.9"
# Importance
bst <- xgboost(   params               = param,
                  data = as.matrix(selectedDf %>% select(-c(Class, clsPred))) ,
                  label =  selectedDf$Class,
                  nrounds             = 100,
                  verbose             = F,
                  prediction          = T,
                  maximize            = F, # Change this value to F will help to run with more itineration
                  nfold               = n_folds,
                  metrics             = c("auc", "error"),
                  early_stopping_rounds = 50,
                  stratified            = T,
                  scale_pos_weight      = 1)
importanceDf <- xgb.importance(colnames(selectedDf %>% select(-c(Class, clsPred))), model = bst)
print(importanceDf)
library(pROC)

dfROC <- pROC::roc(response = ifelse(selectedDf$Class==T, 1, 0),
               predictor = round(xgb_m$pred),
               levels=c(0, 1), direction = "<")

# it = which.max(xgb_m$evaluation_log$test_auc_mean)
# best.iter = xgb_m$evaluation_log$iter[it]
# best.iter 

plot(pROC::roc(response = ifelse(selectedDf$Class==T, 1, 0),
               predictor = round(xgb_m$pred),
               levels=c(0, 1), direction = "<"), 
     legacy.axes = TRUE,
     main="ROC Curve", 
     lwd=1.5) 

Plot feature importance

yAxis <- list(
  title = 'Importance',
  range=c(0.0, 1.0)
)
xAxis <- list(
  title = ''
)

importanceDf$Feature <- factor(importanceDf$Feature, levels = importanceDf[order(-Gain),]$Feature)
fig_Importance <- plot_ly(importanceDf, x = ~Feature, y = ~Gain, type = 'bar', name = 'Gain', width=600) %>%
  add_trace(y = ~Cover, name = 'Cover') %>% 
  add_trace(y = ~Frequency, name = 'Frequency') %>% 
  layout(yaxis = yAxis, xaxis=xAxis, barmode = 'group', title="Feature Importance") %>% 
  config(.Last.value, mathjax = 'cdn')

htmltools::tagList(fig_Importance)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnNvdXJjZSgnLi4vc2V0dGluZ3Mvc2V0dGluZ3MuUicpCnNvdXJjZSgnY29tbW9uRnVuY3Rpb25zLlInKQpsaWJyYXJ5KG5sbWUpCmxpYnJhcnkobG1lNCkKYGBgCgpgYGB7cn0Kc2V0LnNlZWQoNDMpCmRyaXZlMSA8LSByZWFkLmNzdignLi4vZGF0YS9wcm9jZXNzZWQvYW5hbHlzaXMvVFQxX0RyaXZlXzFfUFAuY3N2JykKZHJpdmUyIDwtIHJlYWQuY3N2KCcuLi9kYXRhL3Byb2Nlc3NlZC9BbmFseXNpcy9UVDFfRHJpdmVfMl9QUC5jc3YnKQpkcml2ZTMgPC0gcmVhZC5jc3YoJy4uL2RhdGEvcHJvY2Vzc2VkL0FuYWx5c2lzL1RUMV9Ecml2ZV8zX1BQLmNzdicpCmRyaXZlNCA8LSByZWFkLmNzdignLi4vZGF0YS9wcm9jZXNzZWQvQW5hbHlzaXMvVFQxX0RyaXZlXzRfUFAuY3N2Jywgc3RyaW5nc0FzRmFjdG9ycyA9IFQpCmBgYAoKYGBge3J9CmRmU2VnIDwtIGRhdGEuZnJhbWUocmVwKDEsIG5yb3coZHJpdmU0KSksIHJlcCgyLCBucm93KGRyaXZlNCkpLCByZXAoMywgbnJvdyhkcml2ZTQpKSwgcmVwKDQsIG5yb3coZHJpdmU0KSkpCm5hbWVzKGRmU2VnKSA8LSBjKCJTZWcxIiwgIlNlZzIiLCAiU2VnMyIsICJTZWc0IikKCmNvbWJpbmVkRGZfU2VnMSA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWcxLCBkcml2ZTMkTWVhblBQX1NlZzEsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8xLCBkcml2ZTMkTWVhblBQX1NlZzBfMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMSwgZHJpdmUzJFN0ZFBQX1NlZzEsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMSwgZHJpdmUzJFN0ZFBQX1NlZzBfMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2gxLCBkcml2ZTMkTWVhblBQX0FjY0hpZ2gxLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3cxLCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93MSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDEsIGRyaXZlMyRTdGRQUF9BY2NIaWdoMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93MSwgZHJpdmUzJFN0ZFBQX0FjY0xvdzEsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMQogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnMiA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWcyLCBkcml2ZTMkTWVhblBQX1NlZzIsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8yLCBkcml2ZTMkTWVhblBQX1NlZzBfMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMiwgZHJpdmUzJFN0ZFBQX1NlZzIsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMiwgZHJpdmUzJFN0ZFBQX1NlZzBfMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2gyLCBkcml2ZTMkTWVhblBQX0FjY0hpZ2gyLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3cyLCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93MiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDIsIGRyaXZlMyRTdGRQUF9BY2NIaWdoMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93MiwgZHJpdmUzJFN0ZFBQX0FjY0xvdzIsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMgogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnMyA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWczLCBkcml2ZTMkTWVhblBQX1NlZzMsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8zLCBkcml2ZTMkTWVhblBQX1NlZzBfMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMywgZHJpdmUzJFN0ZFBQX1NlZzMsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMywgZHJpdmUzJFN0ZFBQX1NlZzBfMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2gzLCBkcml2ZTMkTWVhblBQX0FjY0hpZ2gzLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3czLCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93MywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDMsIGRyaXZlMyRTdGRQUF9BY2NIaWdoMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93MywgZHJpdmUzJFN0ZFBQX0FjY0xvdzMsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMwogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnNCA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWc0LCBkcml2ZTMkTWVhblBQX1NlZzQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF80LCBkcml2ZTMkTWVhblBQX1NlZzBfNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnNCwgZHJpdmUzJFN0ZFBQX1NlZzQsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfNCwgZHJpdmUzJFN0ZFBQX1NlZzBfNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2g0LCBkcml2ZTMkTWVhblBQX0FjY0hpZ2g0LAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3c0LCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93NCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDQsIGRyaXZlMyRTdGRQUF9BY2NIaWdoNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93NCwgZHJpdmUzJFN0ZFBQX0FjY0xvdzQsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnNAogICAgICAgICAgICAgICAgICApCgpjb21tb25fbmFtZXMgPC0gYygiUFBfRGV2XzFfVHVybmluZyIsCiAgICAgICAgICAgICAgICAgICJQUF9EZXZfMl9TdHJhaWdodCIsICJQUF9EZXZfM19TdHJhaWdodCIsIAogICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfVHVybmluZyIsICJQUF9EZXZfM19UdXJuaW5nIiwgCiAgICAgICAgICAgICAgICAgICJTdGRfUFBfMl9TdHJhaWdodCIsICJTdGRfUFBfM19TdHJhaWdodCIsIAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfVHVybmluZyIsICJTdGRfUFBfM19UdXJuaW5nIiwKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICJNZWFuX1BQXzJfQWNjSGlnaCIsICJNZWFuX1BQXzNfQWNjSGlnaCIsCiAgICAgICAgICAgICAgICAgICJNZWFuX1BQXzJfQWNjTG93IiwgIk1lYW5fUFBfM19BY2NMb3ciLAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfQWNjSGlnaCIsICJTdGRfUFBfM19BY2NIaWdoIiwKICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX0FjY0xvdyIsICJTdGRfUFBfM19BY2NMb3ciLAogICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgIlNlZ21lbnQiKQoKbmFtZXMoY29tYmluZWREZl9TZWcxKSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKbmFtZXMoY29tYmluZWREZl9TZWcyKSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKbmFtZXMoY29tYmluZWREZl9TZWczKSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKbmFtZXMoY29tYmluZWREZl9TZWc0KSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKCiMgY29tYmluZWREZl9TZWcxJFN1YmplY3QgPC0gcGFzdGUwKGFzLmZhY3Rvcihjb21iaW5lZERmX1NlZzEkU3ViamVjdCksICIuUzEiKQojIGNvbWJpbmVkRGZfU2VnMiRTdWJqZWN0IDwtIHBhc3RlMChhcy5mYWN0b3IoY29tYmluZWREZl9TZWcyJFN1YmplY3QpLCAiLlMyIikKIyBjb21iaW5lZERmX1NlZzMkU3ViamVjdCA8LSBwYXN0ZTAoYXMuZmFjdG9yKGNvbWJpbmVkRGZfU2VnMyRTdWJqZWN0KSwgIi5TMyIpCiMgY29tYmluZWREZl9TZWc0JFN1YmplY3QgPC0gcGFzdGUwKGFzLmZhY3Rvcihjb21iaW5lZERmX1NlZzQkU3ViamVjdCksICIuUzQiKQoKY29tYmluZWREZiA8LSByYmluZChjb21iaW5lZERmX1NlZzEsIGNvbWJpbmVkRGZfU2VnMiwgY29tYmluZWREZl9TZWczLCBjb21iaW5lZERmX1NlZzQpCgojIGNvbWJpbmVkRGYkU3ViamVjdCA8LSBwYXN0ZTAoIiMiLCBzdHJfcGFkKGNvbWJpbmVkRGYkU3ViamVjdCwgMiwgcGFkPSIwIikpCmNvbWJpbmVkRGYkU2VnbWVudCA8LSBhcy5mYWN0b3IoY29tYmluZWREZiRTZWdtZW50KQpjb21iaW5lZERmJEFjdGl2aXR5RW5jb2RlZCA8LSBmYWN0b3IoaWZlbHNlKGNvbWJpbmVkRGYkQWN0aXZpdHkgPT0gIk5PIiwgIjEiLCBpZmVsc2UoY29tYmluZWREZiRBY3Rpdml0eSA9PSAiQyIsICIyIiwgIjMiKSkpCgpjb21iaW5lZERmIDwtIGNvbWJpbmVkRGZbY29tcGxldGUuY2FzZXMoY29tYmluZWREZiksXQpjb21iaW5lZERmJFN1YmplY3QgPSBhcy5mYWN0b3IoY29tYmluZWREZiRTdWJqZWN0KQpgYGAKCgpgYGB7cn0KbW9kZWwgPSBsbShQUF9BZnRlciB+IAogICAgICAgICAgICAgIFBQX0Rldl8yX1N0cmFpZ2h0ICsgCiAgICAgICAgICAgICAgUFBfRGV2XzNfU3RyYWlnaHQgKwogICAgICAgICAgICAgIFBQX0Rldl8yX1R1cm5pbmcgKyAKICAgICAgICAgICAgICBQUF9EZXZfM19UdXJuaW5nICsgCiAgICAgICAgICAgICAgU3RkX1BQXzJfU3RyYWlnaHQgKyAKICAgICAgICAgICAgICBTdGRfUFBfM19TdHJhaWdodCArIAogICAgICAgICAgICAgIFN0ZF9QUF8yX1R1cm5pbmcgKwogICAgICAgICAgICAgIFN0ZF9QUF8zX1R1cm5pbmcgKwogICAgICAgICAgICAgICMgUFBfUHJpb3IgKwogICAgICAgICAgICAgIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLAogICAgICAgICAgICBkYXRhPWNvbWJpbmVkRGYsIHJhbmRvbSA9IH4xfGZhY3RvcihTdWJqZWN0KSwgbWV0aG9kID0gIlJFTUwiKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShtb2RlbCkKcGxvdChtb2RlbCkKYGBgCgojIE5vIFJhbmRvbSBFZmZlY3RzCmBgYHtyfQpsaW5lYXJNb2RlbDEgPC0gbG0oUFBfQWZ0ZXIgfiAKICAgICAgICAgICAgICAgIE1lYW5fUFBfMl9BY2NIaWdoCiAgICAgICAgICAgICAgKyBNZWFuX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBNZWFuX1BQXzNfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0xvdwogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NIaWdoCiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NMb3cKICAgICAgICAgICAgICAjICsgUFBfUHJpb3IKICAgICAgICAgICAgICArIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLAogICAgICAgICAgICBkYXRhPWNvbWJpbmVkRGYpCgojIGFub3ZhKG1vZGVsKQpzdW1tYXJ5KGxpbmVhck1vZGVsMSkKcGxvdChsaW5lYXJNb2RlbDEpCmBgYAoKCiMgV2l0aCBSYW5kb20gRWZmZWN0cwpgYGB7cn0KbGluZWFyTW9kZWwxIDwtIGxtZShQUF9BZnRlciB+IAogICAgICAgICAgICAgICAgTWVhbl9QUF8yX0FjY0hpZ2gKICAgICAgICAgICAgICArIE1lYW5fUFBfMl9BY2NMb3cKICAgICAgICAgICAgICArIE1lYW5fUFBfM19BY2NIaWdoCiAgICAgICAgICAgICAgKyBNZWFuX1BQXzNfQWNjTG93CiAgICAgICAgICAgICAgKyBTdGRfUFBfMl9BY2NIaWdoCiAgICAgICAgICAgICAgKyBTdGRfUFBfMl9BY2NMb3cKICAgICAgICAgICAgICArIFN0ZF9QUF8zX0FjY0hpZ2gKICAgICAgICAgICAgICArIFN0ZF9QUF8zX0FjY0xvdywKICAgICAgICAgICAgICAjICsgZmFjdG9yKEFjdGl2aXR5RW5jb2RlZCksCiAgICAgICAgICAgICAgcmFuZG9tPX4xfGZhY3RvcihTdWJqZWN0KSwKICAgICAgICAgICAgZGF0YT1jb21iaW5lZERmKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShsaW5lYXJNb2RlbDEpCnBsb3QobGluZWFyTW9kZWwxKQpgYGAKCgpgYGB7cn0KbGluZWFyTW9kZWwxIDwtIGxtKFBQX0FmdGVyIH4gCiAgICAgICAgICAgICAgICBNZWFuX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8yX0FjY0xvdwogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0hpZ2gKICAgICAgICAgICAgICArIE1lYW5fUFBfM19BY2NMb3cKICAgICAgICAgICAgICAjICsgUFBfUHJpb3IKICAgICAgICAgICAgICArIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLCAKICAgICAgICAgICAgZGF0YT1jb21iaW5lZERmKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShsaW5lYXJNb2RlbDEpCnBsb3QobGluZWFyTW9kZWwxKQpgYGAKCiMjIE1hY2hpbmUgTGVhcm5pbmcKCmBgYHtyfQpwcEFmdGVyIDwtIGNvbWJpbmVkRGYkUFBfQWZ0ZXIKcHBBZnRlckFycmF5IDwtIG1hdHJpeChwcEFmdGVyLCBucm93ID0gMSxuY29sID0gbGVuZ3RoKHBwQWZ0ZXIpKQogIAp0aHJlc2hvbGRQUEFmdGVyIDwtIG90c3UocHBBZnRlckFycmF5LCByYW5nZT1jKG1pbihwcEFmdGVyKSwgbWF4KHBwQWZ0ZXIpKSkgIyBFeHBlY3RlZCBUaHJlc2hvbGQgPiAwLjEwMTIzCnByaW50KHBhc3RlMCgnVGhyZXNob2xkOiAnLCB0aHJlc2hvbGRQUEFmdGVyKSkKCnNlbGVjdGVkRGYgPC0gY29tYmluZWREZiAlPiUgc2VsZWN0KAogICAgICAgICAgICAgICAgICAiU3ViamVjdCIsICJBY3Rpdml0eSIsICJQUF9BZnRlciIsICMgIlBQX1ByaW9yIiwKICAgICAgICAgICAgICAgICAgIk1lYW5fUFBfMl9BY2NIaWdoIiwgIk1lYW5fUFBfM19BY2NIaWdoIiwKICAgICAgICAgICAgICAgICAgIk1lYW5fUFBfMl9BY2NMb3ciLCAiTWVhbl9QUF8zX0FjY0xvdyIsCiAgICAgICAgICAgICAgICAgICJTdGRfUFBfMl9BY2NIaWdoIiwgIlN0ZF9QUF8zX0FjY0hpZ2giLAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfQWNjTG93IiwgIlN0ZF9QUF8zX0FjY0xvdyIpCgpzZWxlY3RlZERmJFN1YmplY3QgPC0gTlVMTApzZWxlY3RlZERmJEFjdGl2aXR5X05PIDwtIGlmZWxzZShzZWxlY3RlZERmJEFjdGl2aXR5ID09ICJOTyIsIDEsIDApCnNlbGVjdGVkRGYkQWN0aXZpdHlfQyA8LSBpZmVsc2Uoc2VsZWN0ZWREZiRBY3Rpdml0eSA9PSAiQyIsIDEsIDApCnNlbGVjdGVkRGYkQWN0aXZpdHlfTSA8LSBpZmVsc2Uoc2VsZWN0ZWREZiRBY3Rpdml0eSA9PSAiTSIsIDEsIDApCnNlbGVjdGVkRGYkQWN0aXZpdHkgPC0gTlVMTAoKIyBzZWxlY3RlZERmJFBQX0Rldl8xX1R1cm5pbmcgPC0gTlVMTAojIHNlbGVjdGVkRGYkU3RkX1BQXzJfU3RyYWlnaHQgPC0gTlVMTAojIHNlbGVjdGVkRGYkU3RkX1BQXzJfVHVybmluZyA8LSBOVUxMCiMgc2VsZWN0ZWREZiRTdGRfUFBfM19TdHJhaWdodCA8LSBOVUxMCiMgc2VsZWN0ZWREZiRTdGRfUFBfM19UdXJuaW5nIDwtIE5VTEwKIyAKIyAjIEFjY29yZGluZyB0byBMaW5lYXIgbW9kZWwKIyBzZWxlY3RlZERmJFBQX0Rldl8yX1N0cmFpZ2h0IDwtIGFicyhzZWxlY3RlZERmJFBQX0Rldl8yX1N0cmFpZ2h0KQojIHNlbGVjdGVkRGYkUFBfRGV2XzNfU3RyYWlnaHQgPC0gYWJzKHNlbGVjdGVkRGYkUFBfRGV2XzNfU3RyYWlnaHQpCiMgc2VsZWN0ZWREZiRQUF9EZXZfMl9UdXJuaW5nIDwtIGFicyhzZWxlY3RlZERmJFBQX0Rldl8yX1R1cm5pbmcpCiMgc2VsZWN0ZWREZiRQUF9EZXZfM19UdXJuaW5nIDwtIGFicyhzZWxlY3RlZERmJFBQX0Rldl8zX1R1cm5pbmcpCiMgc2VsZWN0ZWREZiRQUF9QcmlvciA8LSBhYnMoc2VsZWN0ZWREZiRQUF9QcmlvcikgIyBOVUxMCgpzZWxlY3RlZERmJENsYXNzIDwtIGlmZWxzZShzZWxlY3RlZERmJFBQX0FmdGVyID49IHRocmVzaG9sZFBQQWZ0ZXIsIFQsIEYpCnNlbGVjdGVkRGYkUFBfQWZ0ZXIgPC0gTlVMTAoKcHJpbnQobmFtZXMoc2VsZWN0ZWREZikpCmBgYAoKYGBge3J9CiMgbGlicmFyeShtZWZhKQojIGNvbWJpbmVkRGYgPC0gcmVwKGNvbWJpbmVkRGYsIDEwKSAKYGBgCgpgYGB7cn0Kc2V0LnNlZWQoMzkpCm5fZm9sZHMgPC0gMTAKcGFyYW1zIDwtIHBhcmFtIDwtIGxpc3Qob2JqZWN0aXZlICAgICAgID0gImJpbmFyeTpsb2dpc3RpYyIsIAogICAgICAgICAgICAgICBib29zdGVyICAgICAgICAgID0gImdidHJlZSIsCiAgICAgICAgICAgICAgIGV2YWxfbWV0cmljICAgICAgPSAiYXVjIiwKICAgICAgICAgICAgICAgZXRhICAgICAgICAgICAgICA9IDAuMSwKICAgICAgICAgICAgICAgbWF4X2RlcHRoICAgICAgICA9IDEwLAogICAgICAgICAgICAgICBhbHBoYSAgICAgICAgICAgID0gMSwKICAgICAgICAgICAgICAgbGFtYmRhICAgICAgICAgICA9IDAsCiAgICAgICAgICAgICAgIGdhbW1hICAgICAgICAgICAgPSAwLjQ1LAogICAgICAgICAgICAgICBtaW5fY2hpbGRfd2VpZ2h0ID0gMC4zLAogICAgICAgICAgICAgICBzdWJzYW1wbGUgICAgICAgID0gMSwKICAgICAgICAgICAgICAgY29sc2FtcGxlX2J5dHJlZSA9IDEpCiAgICAgICAgICAgCiMgWEdCb29zdCBNb2RlbCAgICAgICAgIAp4Z2JfbSA8LSB4Z2IuY3YoICAgcGFyYW1zICAgICAgICAgICAgICAgPSBwYXJhbSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IGFzLm1hdHJpeChzZWxlY3RlZERmICU+JSBzZWxlY3QoLUNsYXNzKSkgLAogICAgICAgICAgICAgICAgICBsYWJlbCA9ICBzZWxlY3RlZERmJENsYXNzLAogICAgICAgICAgICAgICAgICBucm91bmRzICAgICAgICAgICAgID0gMTAwLAogICAgICAgICAgICAgICAgICB2ZXJib3NlICAgICAgICAgICAgID0gRiwKICAgICAgICAgICAgICAgICAgcHJlZGljdGlvbiAgICAgICAgICA9IFQsCiAgICAgICAgICAgICAgICAgIG1heGltaXplICAgICAgICAgICAgPSBGLCAjIENoYW5nZSB0aGlzIHZhbHVlIHRvIEYgd2lsbCBoZWxwIHRvIHJ1biB3aXRoIG1vcmUgaXRpbmVyYXRpb24KICAgICAgICAgICAgICAgICAgbmZvbGQgICAgICAgICAgICAgICA9IG5fZm9sZHMsCiAgICAgICAgICAgICAgICAgIG1ldHJpY3MgICAgICAgICAgICAgPSBjKCJhdWMiLCAiZXJyb3IiKSwKICAgICAgICAgICAgICAgICAgZWFybHlfc3RvcHBpbmdfcm91bmRzID0gNTAsCiAgICAgICAgICAgICAgICAgIHN0cmF0aWZpZWQgICAgICAgICAgICA9IFQsCiAgICAgICAgICAgICAgICAgIHNjYWxlX3Bvc193ZWlnaHQgICAgICA9IDEpCgojIHhnYl9tJGV2YWx1YXRpb25fbG9nW3hnYl9tJGJlc3RfaXRlcmF0aW9uLCJ0ZXN0X2F1Y19tZWFuIl0KeGdiX20kZXZhbHVhdGlvbl9sb2dbeGdiX20kYmVzdF9pdGVyYXRpb24sXQoKYGBgCgojIyBQZXJmb3JtYW5jZSBNZXRyaWNzCmBgYHtyfQojIFByZWRpY3Rpb24Kc2VsZWN0ZWREZiRjbHNQcmVkIDwtIHJvdW5kKHhnYl9tJHByZWQpCgpjb21wdXRlUGVyZm9ybWFuY2VSZXN1bHRzIDwtIGZ1bmN0aW9uKHNkYXQpewogIHNkYXQgPSBzZGF0W2NvbXBsZXRlLmNhc2VzKHNkYXQpLF0KICBhY2MgPSBzdW0oc2RhdFssMV0gPT0gc2RhdFssMl0pL25yb3coc2RhdCkKICBjb25mX21hdCA9IHRhYmxlKHNkYXQpCiAgc3BlY2lmID0gY29uZl9tYXRbMSwxXS9zdW0oY29uZl9tYXRbLDFdKQogIHNlbnNpdiA9IGNvbmZfbWF0WzIsMl0vc3VtKGNvbmZfbWF0WywyXSkKICBwcmVjaSA9ICBjb25mX21hdFsyLDJdL3N1bShjb25mX21hdFsyLF0pCiAgbnB2ID0gICAgY29uZl9tYXRbMSwxXS9zdW0oY29uZl9tYXRbMSxdKQogIHJldHVybihjKGFjYyxzcGVjaWYsc2Vuc2l2LHByZWNpLG5wdikpCn0KCiMgR2V0IGF2ZXJhZ2UgcGVyZm9ybWFuY2UKcGVyZm9ybWFuY2UgPC0gY29tcHV0ZVBlcmZvcm1hbmNlUmVzdWx0cyhzZWxlY3RlZERmICU+JSBzZWxlY3QoQ2xhc3MsIGNsc1ByZWQpKQphY2MgPC0gcGVyZm9ybWFuY2VbMV0KcHJlYyA8LSBwZXJmb3JtYW5jZVs0XQpyZWNhbGwgPC0gcGVyZm9ybWFuY2VbM10Kc3BlYyA8LSBwZXJmb3JtYW5jZVsyXQpucHYgPC0gcGVyZm9ybWFuY2VbNV0KZjEgPC0gKDIgKiByZWNhbGwgKiBwcmVjKSAvIChyZWNhbGwgKyBwcmVjKQphdWMgPC0gYXMubnVtZXJpYyh4Z2JfbSRldmFsdWF0aW9uX2xvZ1t4Z2JfbSRiZXN0X2l0ZXJhdGlvbiwgInRlc3RfYXVjX21lYW4iXSkKCnByaW50KHBhc3RlKCJBY2N1cmFjeT0iLCByb3VuZChhY2MsIDIpKSkKcHJpbnQocGFzdGUoIlByZWNpc2lvbj0iLCByb3VuZChwcmVjLCAyKSkpCnByaW50KHBhc3RlKCJSZWNhbGw9Iiwgcm91bmQocmVjYWxsLCAyKSkpCnByaW50KHBhc3RlKCJTcGVjaWZpY2l0eT0iLCByb3VuZChzcGVjLCAyKSkpCnByaW50KHBhc3RlKCJOUFY9Iiwgcm91bmQobnB2LCAyKSkpCnByaW50KHBhc3RlKCJGMT0iLCByb3VuZChmMSwgMikpKQpwcmludChwYXN0ZSgiQVVDPSIsIHJvdW5kKGF1YywgMikpKQpgYGAKCmBgYHtyfQojIEltcG9ydGFuY2UKYnN0IDwtIHhnYm9vc3QoICAgcGFyYW1zICAgICAgICAgICAgICAgPSBwYXJhbSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IGFzLm1hdHJpeChzZWxlY3RlZERmICU+JSBzZWxlY3QoLWMoQ2xhc3MsIGNsc1ByZWQpKSkgLAogICAgICAgICAgICAgICAgICBsYWJlbCA9ICBzZWxlY3RlZERmJENsYXNzLAogICAgICAgICAgICAgICAgICBucm91bmRzICAgICAgICAgICAgID0gMTAwLAogICAgICAgICAgICAgICAgICB2ZXJib3NlICAgICAgICAgICAgID0gRiwKICAgICAgICAgICAgICAgICAgcHJlZGljdGlvbiAgICAgICAgICA9IFQsCiAgICAgICAgICAgICAgICAgIG1heGltaXplICAgICAgICAgICAgPSBGLCAjIENoYW5nZSB0aGlzIHZhbHVlIHRvIEYgd2lsbCBoZWxwIHRvIHJ1biB3aXRoIG1vcmUgaXRpbmVyYXRpb24KICAgICAgICAgICAgICAgICAgbmZvbGQgICAgICAgICAgICAgICA9IG5fZm9sZHMsCiAgICAgICAgICAgICAgICAgIG1ldHJpY3MgICAgICAgICAgICAgPSBjKCJhdWMiLCAiZXJyb3IiKSwKICAgICAgICAgICAgICAgICAgZWFybHlfc3RvcHBpbmdfcm91bmRzID0gNTAsCiAgICAgICAgICAgICAgICAgIHN0cmF0aWZpZWQgICAgICAgICAgICA9IFQsCiAgICAgICAgICAgICAgICAgIHNjYWxlX3Bvc193ZWlnaHQgICAgICA9IDEpCmltcG9ydGFuY2VEZiA8LSB4Z2IuaW1wb3J0YW5jZShjb2xuYW1lcyhzZWxlY3RlZERmICU+JSBzZWxlY3QoLWMoQ2xhc3MsIGNsc1ByZWQpKSksIG1vZGVsID0gYnN0KQpwcmludChpbXBvcnRhbmNlRGYpCmBgYAoKYGBge3J9CmxpYnJhcnkocFJPQykKCmRmUk9DIDwtIHBST0M6OnJvYyhyZXNwb25zZSA9IGlmZWxzZShzZWxlY3RlZERmJENsYXNzPT1ULCAxLCAwKSwKICAgICAgICAgICAgICAgcHJlZGljdG9yID0gcm91bmQoeGdiX20kcHJlZCksCiAgICAgICAgICAgICAgIGxldmVscz1jKDAsIDEpLCBkaXJlY3Rpb24gPSAiPCIpCgojIGl0ID0gd2hpY2gubWF4KHhnYl9tJGV2YWx1YXRpb25fbG9nJHRlc3RfYXVjX21lYW4pCiMgYmVzdC5pdGVyID0geGdiX20kZXZhbHVhdGlvbl9sb2ckaXRlcltpdF0KIyBiZXN0Lml0ZXIgCgpwbG90KHBST0M6OnJvYyhyZXNwb25zZSA9IGlmZWxzZShzZWxlY3RlZERmJENsYXNzPT1ULCAxLCAwKSwKICAgICAgICAgICAgICAgcHJlZGljdG9yID0gcm91bmQoeGdiX20kcHJlZCksCiAgICAgICAgICAgICAgIGxldmVscz1jKDAsIDEpLCBkaXJlY3Rpb24gPSAiPCIpLCAKICAgICBsZWdhY3kuYXhlcyA9IFRSVUUsCiAgICAgbWFpbj0iUk9DIEN1cnZlIiwgCiAgICAgbHdkPTEuNSkgCmBgYAoKCiMjIyBQbG90IGZlYXR1cmUgaW1wb3J0YW5jZQpgYGB7cn0KeUF4aXMgPC0gbGlzdCgKICB0aXRsZSA9ICdJbXBvcnRhbmNlJywKICByYW5nZT1jKDAuMCwgMS4wKQopCnhBeGlzIDwtIGxpc3QoCiAgdGl0bGUgPSAnJwopCgppbXBvcnRhbmNlRGYkRmVhdHVyZSA8LSBmYWN0b3IoaW1wb3J0YW5jZURmJEZlYXR1cmUsIGxldmVscyA9IGltcG9ydGFuY2VEZltvcmRlcigtR2FpbiksXSRGZWF0dXJlKQpmaWdfSW1wb3J0YW5jZSA8LSBwbG90X2x5KGltcG9ydGFuY2VEZiwgeCA9IH5GZWF0dXJlLCB5ID0gfkdhaW4sIHR5cGUgPSAnYmFyJywgbmFtZSA9ICdHYWluJywgd2lkdGg9NjAwKSAlPiUKICBhZGRfdHJhY2UoeSA9IH5Db3ZlciwgbmFtZSA9ICdDb3ZlcicpICU+JSAKICBhZGRfdHJhY2UoeSA9IH5GcmVxdWVuY3ksIG5hbWUgPSAnRnJlcXVlbmN5JykgJT4lIAogIGxheW91dCh5YXhpcyA9IHlBeGlzLCB4YXhpcz14QXhpcywgYmFybW9kZSA9ICdncm91cCcsIHRpdGxlPSJGZWF0dXJlIEltcG9ydGFuY2UiKSAlPiUgCiAgY29uZmlnKC5MYXN0LnZhbHVlLCBtYXRoamF4ID0gJ2NkbicpCgpodG1sdG9vbHM6OnRhZ0xpc3QoZmlnX0ltcG9ydGFuY2UpCmBgYAoKCg==